// ============================================
// cmd/cli/commands/websocket_serial.go
// ============================================

package commands

import (
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/gorilla/websocket"
	"golang.org/x/term"
)

// SerialWebSocketClient 串口控制台 WebSocket 客户端
type SerialWebSocketClient struct {
	conn      *websocket.Conn
	url       string
	ctx       context.Context
	cancel    context.CancelFunc
	errorChan chan error
}

// SerialMessage 串口控制台消息结构
type SerialMessage struct {
	Type    string `json:"type"`    // 消息类型: data, control, error
	Data    string `json:"data"`    // 消息数据
	Session string `json:"session"` // 会话 ID
}

// NewSerialWebSocketClient 创建新的串口控制台 WebSocket 客户端
func NewSerialWebSocketClient(url string) *SerialWebSocketClient {
	ctx, cancel := context.WithCancel(context.Background())
	return &SerialWebSocketClient{
		url:       url,
		ctx:       ctx,
		cancel:    cancel,
		errorChan: make(chan error, 1),
	}
}

// Connect 连接到 WebSocket 服务器
func (c *SerialWebSocketClient) Connect() error {
	header := http.Header{}
	header.Set("User-Agent", "vmctl-serial-client")

	dialer := websocket.DefaultDialer
	conn, _, err := dialer.Dial(c.url, header)
	if err != nil {
		return fmt.Errorf("failed to connect to WebSocket: %w", err)
	}

	c.conn = conn
	fmt.Printf("Connected to serial console WebSocket: %s\n", c.url)

	return nil
}

// Start 启动 WebSocket 客户端
func (c *SerialWebSocketClient) Start() error {
	if err := c.Connect(); err != nil {
		return err
	}

	// 启动消息接收协程
	go c.receiveMessages()

	// 启动终端输入处理
	go c.handleTerminalInput()

	return nil
}

// receiveMessages 接收 WebSocket 消息
func (c *SerialWebSocketClient) receiveMessages() {
	for {
		select {
		case <-c.ctx.Done():
			return
		default:
			messageType, message, err := c.conn.ReadMessage()
			if err != nil {
				if websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure) {
					c.errorChan <- fmt.Errorf("WebSocket read error: %w", err)
				}
				return
			}

			// 处理不同类型的消息
			switch messageType {
			case websocket.TextMessage:
				// 尝试解析为 JSON，如果失败则作为纯文本处理
				var msg SerialMessage
				if err := json.Unmarshal(message, &msg); err == nil {
					// 成功解析为 JSON，使用结构化的消息处理
					c.handleMessage(msg)
				} else {
					// 作为纯文本处理，直接输出到终端
					fmt.Print(string(message))
				}
			case websocket.BinaryMessage:
				// 二进制消息，直接输出到终端
				fmt.Print(string(message))
			}
		}
	}
}

// handleMessage 处理接收到的消息
func (c *SerialWebSocketClient) handleMessage(msg SerialMessage) {
	switch msg.Type {
	case "data":
		// 输出串口数据到终端
		fmt.Print(msg.Data)
	case "error":
		fmt.Printf("Serial console error: %s\n", msg.Data)
	case "control":
		fmt.Printf("Control message: %s\n", msg.Data)
	default:
		fmt.Printf("Unknown message type: %s\n", msg.Type)
	}
}

// handleTerminalInput 处理终端输入
func (c *SerialWebSocketClient) handleTerminalInput() {
	// 设置终端为原始模式
	oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
	if err != nil {
		fmt.Printf("Failed to set terminal to raw mode: %v\n", err)
		return
	}

	// 使用 defer 确保终端状态被恢复
	defer func() {
		fmt.Println("Restoring terminal state")
		if err := term.Restore(int(os.Stdin.Fd()), oldState); err != nil {
			fmt.Printf("Failed to restore terminal state: %v\n", err)
		}
	}()

	reader := bufio.NewReader(os.Stdin)
	buffer := make([]byte, 1024)

	for {
		select {
		case <-c.ctx.Done():
			fmt.Println("Context done, exiting terminal input handler")
			return
		default:
			n, err := reader.Read(buffer)
			if err != nil {
				if err == io.EOF {
					fmt.Println("EOF reached, exiting terminal input handler")
					return
				}
				fmt.Printf("Failed to read from stdin: %v\n", err)
				continue
			}

			if n > 0 {
				// 检查是否是 Ctrl+] (ASCII 29)
				if n == 1 && buffer[0] == 29 {
					// 先恢复终端状态，再关闭连接
					if err := term.Restore(int(os.Stdin.Fd()), oldState); err != nil {
						fmt.Printf("Failed to restore terminal state: %v", err)
					}
					fmt.Println()
					fmt.Println("Ctrl+] pressed, exiting serial console")
					c.Close()
					return
				}

				// 发送输入数据到串口控制台
				if err := c.SendData(string(buffer[:n])); err != nil {
					fmt.Printf("Failed to send message: %v\n", err)
				}
			}
		}
	}
}

// SendMessage 发送消息到 WebSocket 服务器
func (c *SerialWebSocketClient) SendMessage(msg SerialMessage) error {
	data, err := json.Marshal(msg)
	if err != nil {
		return fmt.Errorf("failed to marshal message: %w", err)
	}

	if err := c.conn.WriteMessage(websocket.TextMessage, data); err != nil {
		return fmt.Errorf("failed to write message: %w", err)
	}
	return nil
}

// SendData 发送数据到串口控制台
func (c *SerialWebSocketClient) SendData(data string) error {
	// 直接发送纯文本数据，因为服务器期望的是纯文本
	if err := c.conn.WriteMessage(websocket.TextMessage, []byte(data)); err != nil {
		return fmt.Errorf("failed to write data: %w", err)
	}
	return nil
}

// Wait 等待客户端结束
func (c *SerialWebSocketClient) Wait() error {
	select {
	case err := <-c.errorChan:
		return err
	case <-c.ctx.Done():
		return nil
	}
}

// Close 关闭 WebSocket 连接
func (c *SerialWebSocketClient) Close() error {
	c.cancel()

	// 在关闭连接前，确保终端状态被正确恢复
	// 这里不能直接调用 term.Restore，因为需要原始的 oldState
	// 但我们可以通过其他方式确保终端状态被恢复

	if c.conn != nil {
		// 发送关闭消息
		msg := SerialMessage{
			Type: "control",
			Data: "disconnect",
		}
		if err := c.SendMessage(msg); err != nil {
			fmt.Printf("Failed to send disconnect message: %v", err)
		}

		// 关闭 WebSocket 连接
		err := c.conn.WriteMessage(websocket.CloseMessage,
			websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
		if err != nil {
			fmt.Printf("Failed to send close message: %v", err)
		}

		return c.conn.Close()
	}

	return nil
}

// RunSerialConsole 运行串口控制台交互
func RunSerialConsole(wsURL string) error {
	client := NewSerialWebSocketClient(wsURL)

	// 设置信号处理
	setupSignalHandler(client)

	// 启动客户端
	if err := client.Start(); err != nil {
		return fmt.Errorf("failed to start serial console: %w", err)
	}

	fmt.Println("Serial console connected. Press Ctrl+] to exit.")
	fmt.Println("----------------------------------------------")

	// 等待客户端结束
	if err := client.Wait(); err != nil {
		return fmt.Errorf("serial console error: %w", err)
	}

	return nil
}

// setupSignalHandler 设置信号处理器
func setupSignalHandler(client *SerialWebSocketClient) {
	sigChan := make(chan os.Signal, 1)
	// 监听 SIGINT (Ctrl+C), SIGTERM
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		sig := <-sigChan
		fmt.Printf("Received signal: %v\n", sig)
		client.Close()
	}()
}
